Language Reference / Classes and Objects
Traits Composed(結合) from Traits
<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
}
trait World {
public function sayWorld() {
echo 'World!';
}
}
trait HelloWorld {
use Hello, World;
}
class MyHelloWorld {
use HelloWorld;
}
$o = new MyHelloWorld();
$o->sayHello(); //Hello
$o->sayWorld(); //World
?>
Examples: Static Variables
<?php
trait Counter {
public function inc() {
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
}
class C1 {
use Counter;
}
class C2 {
use Counter;
}
$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>
Examples: Static Method
<?php
trait StaticExample {
public static function doSomething() {
return 'Doing something';
}
}
class Example {
use StaticExample;
}
echo Example::doSomething(); 'Doing something'
?>
Examples: Defining Properties
<?php
trait PropertiesTrait {
public $x = 1;
}
class PropertiesExample {
use PropertiesTrait;
}
$example = new PropertiesExample;
echo $example->x; // 1
?>
Examples: Conflict Resolution
<?php
trait PropertiesTrait {
public $same = true;
public $different = false;
}
class PropertiesExample {
use PropertiesTrait;
public $same = true; // Allowed as of PHP 7.0.0; E_STRICT notice formerly
public $different = true; // Fatal error
}
?>
Anonymous classes
Examples: extend other classes, implement interfaces, and use traits just like a normal class
<?php
class SomeClass {}
interface SomeInterface {}
trait SomeTrait {}
var_dump(new class(10) extends SomeClass implements SomeInterface {
private $num;
public function __construct($num)
{
$this->num = $num;
}
use SomeTrait;
});
/*
object(class@anonymous)#1 (1) {
["Command line code0x104c5b612":"class@anonymous":private]=>
int(10)
}
*/
Examples: Nesting an anonymous class within another class does not give it access to any private or protected methods or properties of that outer class => the anonymous class can extend the outer class
<?php
class Outer
{
private $prop = 1;
protected $prop2 = 2;
protected function func1()
{
return 3;
}
public function func2()
{
return new class($this->prop) extends Outer {
private $prop3;
public function __construct($prop)
{
$this->prop3 = $prop;
}
public function func3()
{
return $this->prop2 + $this->prop3 + $this->func1();
}
};
}
}
echo (new Outer)->func2()->func3(); // 6
Examples: All objects created by the same anonymous class declaration are instances of that very class.
<?php
function anonymous_class()
{
return new class {};
}
if (get_class(anonymous_class()) === get_class(anonymous_class())) {
echo 'same class';
} else {
echo 'different class';
}
//same class
Examples: anonymous classes are assigned a name by the engine
<?php
echo get_class(new class {}); //class@anonymous/in/oNi1A0x7f8636ad2021
Object Iteration
PHP 5 provides a way for objects to be defined so it is possible to iterate through a list of items
Examples: Simple Object Iteration
class MyClass {
public $var1 = 'value 1';
public $var2 = 'value 2';
public $var3 = 'value 3';
protected $protected = 'protected var';
private $private = 'private var';
function iterateVisible() {
echo "MyClass::interateVisible:\n";
foreach ($this as $key => $value) {
print "{$key} => {$value}\n";
}
}
}
$class = new MyClass();
foreach($class as $key => $value) {
print "{$key} => {$value}\n";
}
/*
var1 => value 1
var2 => value 2
var3 => value 3
*/
$class->iterateVisible();
/*
MyClass::iterateVisible:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var
*/
Examples: Object Iteration implementing Iterator ??
<?php
class MyIterator implements Iterator
{
private $var = array();
public function __construct($array)
{
if (is_array($array)) {
$this->var = $array;
}
}
public function rewind()
{
echo "rewinding\n";
reset($this->var);
}
public function current()
{
$var = current($this->var);
echo "current: $var\n";
return $var;
}
public function key()
{
$var = key($this->var);
echo "key: $var\n";
return $var;
}
public function next()
{
$var = next($this->var);
echo "next: $var\n";
return $var;
}
public function valid()
{
$key = key($this->var);
$var = ($key !== NULL && $key !== FALSE);
echo "valid: $var\n";
return $var;
}
}
$values = array(1,2,3);
$it = new MyIterator($values);
foreach ($it as $a => $b) {
print "$a: $b\n";
}
/*
rewinding
valid: 1
current: 1
key: 0
0: 1
next: 2
valid: 1
current: 2
key: 1
1: 2
next: 3
valid: 1
current: 3
key: 2
2: 3
next:
valid:
*/
?>
Examples: Object Iteration implementing IteratorAggregate ??
<?php
class MyCollection implements IteratorAggregate
{
private $items = array();
private $count = 0;
// Required definition of interface IteratorAggregate
public function getIterator() {
return new MyIterator($this->items);
}
public function add($value) {
$this->items[$this->count++] = $value;
}
}
$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');
foreach ($coll as $key => $val) {
echo "key/value: [$key -> $val]\n\n";
}
/*
rewinding
current: value 1
valid: 1
current: value 1
key: 0
key/value: [0 -> value 1]
next: value 2
current: value 2
valid: 1
current: value 2
key: 1
key/value: [1 -> value 2]
next: value 3
current: value 3
valid: 1
current: value 3
key: 2
key/value: [2 -> value 3]
next:
current:
valid:
*/
?>
Magic Methods
__toString()
Examples: Simple example
<?php
// Declare a simple class
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class; // Hello
?>
Examples: Using __invoke()
The __invoke() method is called when a script tries to call an object as a function.
<?php
class CallableClass
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5); // int(5)
var_dump(is_callable($obj));// bool(true)
?>
Examples: Using __set_state() (since PHP 5.1.0)
<?php
class A
{
public $var1;
public $var2;
public static function __set_state($an_array) // As of PHP 5.1.0
{
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));
var_dump($b);
?>
Examples: Using __debugInfo()
This method is called by var_dump() when dumping an object to get the properties that should be shown. If the method isn't defined on an object, then all public, protected and private properties will be shown.
<?php
class C {
private $prop;
public function __construct($val) {
$this->prop = $val;
}
public function __debugInfo() {
return [
'propSquared' => $this->prop ** 2,
];
}
}
var_dump(new C(42));
/*
object(C)#1 (1) {
["propSquared"]=>
int(1764)
}
*/
Note:
- PHP reserves all function names starting with __ as magical. It is recommended that you do not use function names with __ in PHP unless you want some documented magic functionality
Final Keyword
- which prevents child classes from overriding a method by prefixing the definition with final
- If the class itself is being defined final then it cannot be extended
Examples: Final methods example
<?php
class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}
final public function moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo "ChildClass::moreTesting() called\n"; // Results in Fatal error: Cannot override final method BaseClass::moreTesting()
}
}
?>
Examples: Final class example2
<?php
final class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}
// Here it doesn't matter if you specify the function as final or not
final public function moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass {
}
// Results in Fatal error: Class ChildClass may not inherit from final class (BaseClass)
?>
Note:
- Properties cannot be declared final, only classes and methods may be declared as final.
Object Cloning
An object copy is created by using the clone keyword (which calls the object's __clone() method if possible). An object's __clone() method cannot be called directly. => Ex: $copy_of_object = clone $object;
Questions:
<?php
class SubObject
{
static $instances = 0;
public $instance;
public function __construct() {
$this->instance = ++self::$instances;
}
public function __clone() {
$this->instance = ++self::$instances;
}
}
class MyCloneable
{
public $object1;
public $object2;
function __clone()
{
// Force a copy of this->object, otherwise
// it will point to same object.
$this->object1 = clone $this->object1;
}
}
$obj = new MyCloneable();
$obj->object1 = new SubObject(); // 初始化第一次
$obj->object2 = new SubObject(); // 初始化第二次
$obj2 = clone $obj; // clone 第三次
print("Original Object:\n");
print_r($obj);
print("Cloned Object:\n");
print_r($obj2);
/*
Original Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)
[object2] => SubObject Object
(
[instance] => 2
)
)
Cloned Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)
[object2] => SubObject Object
(
[instance] => 2
)
)
*/
?>
Examples: Access member of freshly cloned object
<?php
$dateTime = new DateTime();
echo (clone $dateTime)->format('Y'); // 2016
?>